package personal.parser;


import java.util.Set;

/**
 * 语法分析的自动机
 */
public interface ParserFA {

    interface Item {
        /**
         * @return 产生式
         */
        Grammar.Production production();

        /**
         * @return 下一位集合
         */
        Set<Grammar.Terminal> lookahead();

        /**
         * @return 返回等待的下一个 Symbol
         * @throws IndexOutOfBoundsException 到达产生式末尾，即是可归约的
         */
        Grammar.Symbol getCurrent() throws IndexOutOfBoundsException;

        /**
         * @return 返回等待的下一个 Symbol。如果是可归约状态，则会返回 null
         */
        Grammar.Symbol getCurrentOrNull();
    }

    /**
     * 状态，即自动机的节点，包含多条 item
     */
    interface Status {
        /**
         * @return 当前状态的相关转移
         */
        Set<Grammar.Symbol> getCurrents();

        /**
         * @return 节点的 item 集合
         */
        Set<Item> Items();

        /**
         * @return 是否是可归约的
         */
        boolean isReducible();

        /**
         * @return 是否存在移入-归约冲突
         */
        boolean haveSRConflict();

        /**
         * @return 是否存在归约-归约冲突
         */
        boolean haveRRConflict();


    }

    /**
     * @return FA 的节点数量
     */
    int size();

    /**
     * @param id 节点编号
     * @return 编号对应的节点
     */
    Status getStatus(int id);

    /**
     * @param node 节点
     * @return 节点对应的编号
     */
    int indexOf(Status node);

    /**
     * @param id 转移符号的编号
     * @return 编号对应的转移符号
     */
    Grammar.Symbol getSymbol(int id);

    /**
     * @param symbol 转移符号
     * @return 转移符号对应的编号
     */
    int indexOf(Grammar.Symbol symbol);

    /**
     * 进行一次转移
     *
     * @param u       转移起点
     * @param transit 转移符号
     * @return 转移到的节点
     * @throws NullPointerException 没有相关的转移
     */
    Status transitTo(Status u, Grammar.Symbol transit) throws NullPointerException;

    /**
     * 进行一次转移
     *
     * @param u       转移起点
     * @param transit 转移符号
     * @return 转移到的节点
     * @throws NullPointerException 没有相关的转移
     */
    int transitTo(int u, Grammar.Symbol transit) throws NullPointerException;

}
